#include "stdafx.h"
#include "BufferedSocket.h"
#include "Log.h"
#include "System.h"

namespace Core
{
	BufferedSocket::BufferedSocket(Socket p_Socket) : Socket(p_Socket)
	{
		m_BufferedSocketListener = NULL;
	}

	BufferedSocket::~BufferedSocket()
	{
	}

	bool BufferedSocket::IsReceiverEmpty()
	{
		return (m_ReceiverBuffer.size()==0);
	}

	bool BufferedSocket::IsSenderEmpty()
	{
		return (m_SenderBuffer.size()==0);
	}

	void BufferedSocket::SetListener(BufferedSocketListener* p_BufferedSocketListener)
	{
		m_BufferedSocketListener = p_BufferedSocketListener;
	}

	void BufferedSocket::Receiver()
	{
		RawData t_RawData;
		InternetAddress t_ReceiverUDPInternetAddress;
		while(m_Active)
		{
		    System::MilliSleep(1);
			t_RawData.Reset();
			try
			{
				if(m_Protocol==Protocol_Tcp)
				{
					if(!Socket::Receive(t_RawData, 1000)) continue;
				}
				else if(m_Protocol==Protocol_Udp)
				{
					if(!Socket::ReceiveFrom(t_RawData, t_ReceiverUDPInternetAddress, 1000)) continue;
				}
			}
			catch(...)
			{
				Close();
				if(m_BufferedSocketListener)
				{
					m_BufferedSocketListener->ConnectionClosed();
				}
				break;
			}
			m_ReceiverMutex.Lock();
			m_ReceiverBuffer.push(t_RawData);
			m_ReceiverAddressBuffer.push(t_ReceiverUDPInternetAddress);
			m_ReceiverMutex.Unlock();
			if(m_BufferedSocketListener)
			{
				m_BufferedSocketListener->MessageReceived();
			}
		}
		//Log::GetSingleton().Write(LogLevel_Info, "End Receiver");
	}

	void BufferedSocket::Sender()
	{
		RawData t_RawData;
		InternetAddress t_SenderUDPInternetAddress;
		while(m_Active)
		{
			System::MilliSleep(1);
			if(m_SenderBuffer.size()==0)
			{
				continue;
			}
			t_RawData.Reset();
			m_SenderMutex.Lock();
			t_RawData = m_SenderBuffer.front();
			m_SenderBuffer.pop();
			t_SenderUDPInternetAddress = m_SenderAddressBuffer.front();
			m_SenderAddressBuffer.pop();
			m_SenderMutex.Unlock();
			bool t_Sent = false;
			while(!t_Sent)
			{
				try
				{
					if(m_Protocol==Protocol_Tcp)
					{
						if(!Socket::Send(t_RawData, 1000)) continue;
					}
					else if(m_Protocol==Protocol_Udp)
					{
						if(!Socket::SendTo(t_RawData, t_SenderUDPInternetAddress, 1000)) continue;
					}
					t_Sent = true;
				}
				catch(...)
				{
					Close();
					if(m_BufferedSocketListener)
					{
						m_BufferedSocketListener->ConnectionClosed();
					}
					break;
				}
			}
			if(m_BufferedSocketListener)
			{
				m_BufferedSocketListener->MessageSent();
			}
		}
		//Log::GetSingleton().Write(LogLevel_Info, "End Sender");
	}

	bool BufferedSocket::Receive(RawData& p_RawData, int p_TimeOutMilliSeconds)
	{
		InternetAddress t_InternetAddress;
		return ReceiveFrom(p_RawData, t_InternetAddress, p_TimeOutMilliSeconds);
	}

	bool BufferedSocket::ReceiveFrom(RawData& p_RawData, InternetAddress& p_InternetAddress, int p_TimeOutMilliSeconds)
	{
		if(m_ReceiverBuffer.size()==0)
		{
			return false;
		}
		m_ReceiverMutex.Lock();
		p_RawData = m_ReceiverBuffer.front();
		m_ReceiverBuffer.pop();
		p_InternetAddress = m_ReceiverAddressBuffer.front();
		m_ReceiverAddressBuffer.pop();
		m_ReceiverMutex.Unlock();
		return true;
	}

	bool BufferedSocket::Send(RawData& p_RawData, int p_TimeOutMilliSeconds)
	{
		InternetAddress t_InternetAddress;
		return SendTo(p_RawData, t_InternetAddress, p_TimeOutMilliSeconds);
	}

	bool BufferedSocket::SendTo(RawData& p_RawData, InternetAddress& p_InternetAddress, int p_TimeOutMilliSeconds)
	{
		m_SenderMutex.Lock();
		m_SenderBuffer.push(p_RawData);
		m_SenderAddressBuffer.push(p_InternetAddress);
		m_SenderMutex.Unlock();
		return true;
	}

	void BufferedSocket::StartAll()
	{
		StartReceiver();
		StartSender();
	}

	void BufferedSocket::StartReceiver()
	{
		m_Receiver.Start(this, &BufferedSocket::Receiver);
	}

	void BufferedSocket::StartSender()
	{
		m_Sender.Start(this, &BufferedSocket::Sender);
	}

	void BufferedSocket::StopAll()
	{
		Close();
		//m_Receiver.Exit();
		//m_Sender.Exit();
	}
}
